package com.example.service.impl;

import com.example.entity.auth.Account;
import com.example.mapper.UserMapper;
import com.example.service.AuthorizeService;
import jakarta.annotation.Resource;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Lazy;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.mail.MailException;
import org.springframework.mail.MailSender;
import org.springframework.mail.SimpleMailMessage;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.stereotype.Service;

import java.util.Optional;
import java.util.Random;
import java.util.concurrent.TimeUnit;

/**
 * @author AiXu
 * @version v1.0
 * @since 2023/9/11 16:09
 */

@Service
public class AuthorizeServiceImpl implements AuthorizeService {

    @Value("${spring.mail.username}")
    String from;

    @Resource
    private UserMapper userMapper;

    @Resource
    private MailSender mailSender;

    @Resource
    private StringRedisTemplate stringRedisTemplate;

    @Lazy
    @Resource
    private BCryptPasswordEncoder bCryptPasswordEncoder;

    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        if (username == null) {
            throw new UsernameNotFoundException("用户名不能为空");
        }
        Account account = userMapper.findAccountByNameOrEmail(username);
        if (account == null) {
            throw new UsernameNotFoundException("用户名或密码错误");
        }
        return User
                .withUsername(account.getUsername())
                .password(account.getPassword())
                .roles("user")
                .build();
    }

    /**
     * 1，先生成验证码
     * 2，发送验证码到邮箱
     * 3，如果发送成功，把邮箱和对应的验证码直接放到redis里 （过期时间3分钟，）
     * 4，用户注册时，再Redis里取出对应的键值对，然后查看验证码是否一致
     *
     * @param email
     * @param sessionID
     * @return null:请求成功
     */
    @Override
    public String sendValidatedEmail(String email, String sessionID, boolean hasAccount) {
        String key = "email:" + sessionID + ":" + email + ":" + hasAccount;
        if (Boolean.TRUE.equals(stringRedisTemplate.hasKey(key))) {
            Long expire = Optional.ofNullable(stringRedisTemplate.getExpire(key, TimeUnit.SECONDS)).orElse(0L);
            if (expire > 120) return "请勿重复获取验证码";
        }
        Account account = userMapper.findAccountByNameOrEmail(email);
        if (hasAccount && account == null) return "没有此邮箱地址用户";
        if (!hasAccount && account != null) return "邮箱已被注册";
        Random random = new Random();
        int code = random.nextInt(89999) + 100000;
        SimpleMailMessage mailMessage = new SimpleMailMessage();
        mailMessage.setFrom(from);
        mailMessage.setTo(email);
        mailMessage.setSubject("您的验证邮件");
        mailMessage.setText("验证码是：" + code);
        try {
            mailSender.send(mailMessage);

            stringRedisTemplate.opsForValue().set(key, String.valueOf(code), 3, TimeUnit.MINUTES);
            return null;
        } catch (MailException e) {
            // todo 警告:(85, 15) 对 'printStackTrace()' 的调用可能应当替换为更可靠的日志
            e.printStackTrace();
            return "邮件发送失败，请联系管理员";
        }
    }

    /**
     * @param username
     * @param password
     * @param email
     * @param code
     * @return null: 请求成功
     */
    @Override
    public String validateAndRegister(String username, String password, String email, String code, String sessionID) {
        // 对比验证码
        String key = "email:" + sessionID + ":" + email + ":false";
        if (Boolean.TRUE.equals(stringRedisTemplate.hasKey(key))) {
            String s = stringRedisTemplate.opsForValue().get(key);
            if (s == null) return "验证码获取失败，请重新获取";
            if (s.equals(code)) {
                // 将密码进行编码后存储
                password = bCryptPasswordEncoder.encode(password);
                //
                stringRedisTemplate.delete(key);
                int createAccount = userMapper.createAccount(username, password, email);
                if (createAccount > 0) return null;
                else return "内部错误，请联系管理员";
            } else return "验证码错误，请检查后重新提交";
        } else return "请先获取验证码";
    }

    @Override
    public String validateOnly(String email, String code, String sessionID) {
        String key = "email:" + sessionID + ":" + email + ":true";
        if (Boolean.TRUE.equals(stringRedisTemplate.hasKey(key))) {
            String s = stringRedisTemplate.opsForValue().get(key);
            if (s == null) return "验证码获取失败，请重新获取";
            if (s.equals(code)) {
                stringRedisTemplate.delete(key);
                return null;
            }
            else return "验证码错误，请检查后重新提交";
        } else return "请先获取验证码";
    }

    @Override
    public boolean resetPassword(String email, String password) {
        password = bCryptPasswordEncoder.encode(password);
        return userMapper.resetPasswordByEmail(password,email) > 0;
    }

}
